{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 02图像卷积"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:26.587988Z",
     "iopub.status.busy": "2023-08-18T07:07:26.587419Z",
     "iopub.status.idle": "2023-08-18T07:07:28.559553Z",
     "shell.execute_reply": "2023-08-18T07:07:28.558681Z"
    },
    "origin_pos": 2,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch import nn\n",
    "from d2l import torch as d2l"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:28.563668Z",
     "iopub.status.busy": "2023-08-18T07:07:28.562986Z",
     "iopub.status.idle": "2023-08-18T07:07:28.569424Z",
     "shell.execute_reply": "2023-08-18T07:07:28.568319Z"
    },
    "origin_pos": 4,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [],
   "source": [
    "def corr2d(X, K):  #@save\n",
    "    \"\"\"计算二维互相关运算\"\"\"\n",
    "    h, w = K.shape\n",
    "    Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))\n",
    "    for i in range(Y.shape[0]):\n",
    "        for j in range(Y.shape[1]):\n",
    "            Y[i, j] = (X[i:i + h, j:j + w] * K).sum()\n",
    "    return Y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:28.572958Z",
     "iopub.status.busy": "2023-08-18T07:07:28.572449Z",
     "iopub.status.idle": "2023-08-18T07:07:28.604854Z",
     "shell.execute_reply": "2023-08-18T07:07:28.603813Z"
    },
    "origin_pos": 7,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[19., 25.],\n",
       "        [37., 43.]])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])\n",
    "K = torch.tensor([[0.0, 1.0], [2.0, 3.0]])\n",
    "corr2d(X, K)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:28.610672Z",
     "iopub.status.busy": "2023-08-18T07:07:28.609819Z",
     "iopub.status.idle": "2023-08-18T07:07:28.615602Z",
     "shell.execute_reply": "2023-08-18T07:07:28.614632Z"
    },
    "origin_pos": 10,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [],
   "source": [
    "class Conv2D(nn.Module):\n",
    "    def __init__(self, kernel_size):\n",
    "        super().__init__()\n",
    "        self.weight = nn.Parameter(torch.rand(kernel_size))\n",
    "        self.bias = nn.Parameter(torch.zeros(1))\n",
    "\n",
    "    def forward(self, x):\n",
    "        return corr2d(x, self.weight) + self.bias"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:28.620077Z",
     "iopub.status.busy": "2023-08-18T07:07:28.619277Z",
     "iopub.status.idle": "2023-08-18T07:07:28.626719Z",
     "shell.execute_reply": "2023-08-18T07:07:28.625746Z"
    },
    "origin_pos": 14,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[1., 1., 0., 0., 0., 0., 1., 1.],\n",
       "        [1., 1., 0., 0., 0., 0., 1., 1.],\n",
       "        [1., 1., 0., 0., 0., 0., 1., 1.],\n",
       "        [1., 1., 0., 0., 0., 0., 1., 1.],\n",
       "        [1., 1., 0., 0., 0., 0., 1., 1.],\n",
       "        [1., 1., 0., 0., 0., 0., 1., 1.]])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X = torch.ones((6, 8))\n",
    "X[:, 2:6] = 0\n",
    "X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:28.630101Z",
     "iopub.status.busy": "2023-08-18T07:07:28.629606Z",
     "iopub.status.idle": "2023-08-18T07:07:28.634133Z",
     "shell.execute_reply": "2023-08-18T07:07:28.633165Z"
    },
    "origin_pos": 17,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [],
   "source": [
    "K = torch.tensor([[1.0, -1.0]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:28.639056Z",
     "iopub.status.busy": "2023-08-18T07:07:28.638505Z",
     "iopub.status.idle": "2023-08-18T07:07:28.646532Z",
     "shell.execute_reply": "2023-08-18T07:07:28.645509Z"
    },
    "origin_pos": 19,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 0.,  1.,  0.,  0.,  0., -1.,  0.],\n",
       "        [ 0.,  1.,  0.,  0.,  0., -1.,  0.],\n",
       "        [ 0.,  1.,  0.,  0.,  0., -1.,  0.],\n",
       "        [ 0.,  1.,  0.,  0.,  0., -1.,  0.],\n",
       "        [ 0.,  1.,  0.,  0.,  0., -1.,  0.],\n",
       "        [ 0.,  1.,  0.,  0.,  0., -1.,  0.]])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Y = corr2d(X, K)\n",
    "Y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:28.651371Z",
     "iopub.status.busy": "2023-08-18T07:07:28.650819Z",
     "iopub.status.idle": "2023-08-18T07:07:28.658419Z",
     "shell.execute_reply": "2023-08-18T07:07:28.657436Z"
    },
    "origin_pos": 21,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0., 0., 0., 0., 0.],\n",
       "        [0., 0., 0., 0., 0.],\n",
       "        [0., 0., 0., 0., 0.],\n",
       "        [0., 0., 0., 0., 0.],\n",
       "        [0., 0., 0., 0., 0.],\n",
       "        [0., 0., 0., 0., 0.],\n",
       "        [0., 0., 0., 0., 0.],\n",
       "        [0., 0., 0., 0., 0.]])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "corr2d(X.t(), K)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:28.662260Z",
     "iopub.status.busy": "2023-08-18T07:07:28.661527Z",
     "iopub.status.idle": "2023-08-18T07:07:28.681412Z",
     "shell.execute_reply": "2023-08-18T07:07:28.680192Z"
    },
    "origin_pos": 24,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 2, loss 6.422\n",
      "epoch 4, loss 1.225\n",
      "epoch 6, loss 0.266\n",
      "epoch 8, loss 0.070\n",
      "epoch 10, loss 0.022\n"
     ]
    }
   ],
   "source": [
    "# 构造一个二维卷积层，它具有1个输出通道和形状为（1，2）的卷积核\n",
    "conv2d = nn.Conv2d(1,1, kernel_size=(1, 2), bias=False)\n",
    "\n",
    "# 这个二维卷积层使用四维输入和输出格式（批量大小、通道、高度、宽度），\n",
    "# 其中批量大小和通道数都为1\n",
    "X = X.reshape((1, 1, 6, 8))\n",
    "Y = Y.reshape((1, 1, 6, 7))\n",
    "lr = 3e-2  # 学习率\n",
    "\n",
    "for i in range(10):\n",
    "    Y_hat = conv2d(X)\n",
    "    l = (Y_hat - Y) ** 2\n",
    "    conv2d.zero_grad()\n",
    "    l.sum().backward()\n",
    "    # 迭代卷积核\n",
    "    conv2d.weight.data[:] -= lr * conv2d.weight.grad\n",
    "    if (i + 1) % 2 == 0:\n",
    "        print(f'epoch {i+1}, loss {l.sum():.3f}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:28.684721Z",
     "iopub.status.busy": "2023-08-18T07:07:28.684428Z",
     "iopub.status.idle": "2023-08-18T07:07:28.691507Z",
     "shell.execute_reply": "2023-08-18T07:07:28.690512Z"
    },
    "origin_pos": 29,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 1.0010, -0.9739]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conv2d.weight.data.reshape((1, 2))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  },
  "required_libs": []
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
